Skip to content

feat(gui): add mobile palette drawer toggle (Phase 2-D of #572, drag-close TODO)#585

Merged
takaokouji merged 4 commits into
developfrom
fix/issue-572-phase-2d-palette-drawer
Apr 29, 2026
Merged

feat(gui): add mobile palette drawer toggle (Phase 2-D of #572, drag-close TODO)#585
takaokouji merged 4 commits into
developfrom
fix/issue-572-phase-2d-palette-drawer

Conversation

@takaokouji
Copy link
Copy Markdown

Summary

issue #572 Phase 2-D: ブロックパレットのドロワー化 (最小実装)。

実装

新規コンポーネント: MobilePaletteToggle

  • 既存の Smalruby palette-visibility Redux state (paletteVisible) を利用
  • position: fixed で viewport 左端に追従 (visualViewport API、MobileTopBar の高さ分下にオフセット)
  • 表示条件: ?mobile_gui=1 + Code タブ + 全画面でない とき のみ
  • クリックで togglePalette() ディスパッチ (◀ / ▶ ハンドル)
  • 初回マウント時 (= mobile_gui モードに入った直後) に自動で hidePalette() を呼ぶ
    • 狭幅画面ではパレットが workspace を圧迫するため、デフォルト非表示

MobileGui への組み込み

<MobileTopBar /> / <MobileBottomTabs /> に並んで <MobilePaletteToggle /> を追加。

upstream への影響

なしpalette-visibility reducer は元々 Smalruby 側で持っているため、upstream のファイルは触らない。

未対応 (フォローアップ予定)

⚠️ 「ブロックドラッグ開始時に自動クローズ」は本 PR には含まれません。

Blocklyworkspace.addChangeListener から drag start イベントを検知して hidePalette() を呼ぶ実装は、ScratchBlocks へのアクセスが必要 (blocks-gesture-recovery と同じパターン)。設計と実装ボリュームが drawer 自体より大きいため、別 PR で対応する想定。

現状でも palette を ◀ ハンドルで明示的に閉じればドラッグ操作の妨げにはならない。

変更ファイル

新規 (Smalruby 固有)

  • src/components/mobile-palette-toggle/{mobile-palette-toggle.jsx,css,index.js}
  • test/unit/components/mobile-palette-toggle.test.jsx — 8 ユニットテスト

変更

  • src/components/mobile-gui/mobile-gui.jsx<MobilePaletteToggle /> を追加 (1 行)

メタファイル

  • .prettierignore / smalruby-prettier-files.md — 新規ファイルをホワイトリストに追加

検証

ユニットテスト (jest, 8 件)

  • Code タブで描画される
  • Ruby タブでは描画されない
  • 全画面では描画されない
  • paletteVisible=true で ◀ 表示
  • paletteVisible=false で ▶ 表示
  • クリックで onToggle 呼出
  • マウント時に visible なら onAutoHide 1 回呼出
  • マウント時に visible でなければ onAutoHide 呼ばれない

Playwright (Chromium, viewport 390×844)

シナリオ 結果
?mobile_gui=1 で初期表示 パレット非表示、▶ ハンドル左端 ✓
▶ クリック パレット表示、ハンドル ◀ ✓
◀ クリック パレット非表示、ハンドル ▶ ✓

Phase 2 進捗

Test plan

  • ユニットテスト 8/8 緑
  • ESLint / Prettier クリーン
  • Playwright で動作確認
  • mobile_gui=1 無し では既存挙動を維持
  • CI green (push 後)

🤖 Generated with Claude Code

issue #572 Phase 2-D: ブロックパレットのドロワー化を最小実装。

実装:
- 新規 MobilePaletteToggle コンポーネント (Smalruby 固有)
  - 既存の Smalruby palette-visibility Redux state を利用
  - position: fixed で viewport 左端に追従 (visualViewport API)
  - Code タブ + 全画面でないとき のみ表示
  - クリックで togglePalette() ディスパッチ
  - 初回マウント時 (= mobile_gui モード突入時) に自動的に hidePalette()
- MobileGui に <MobilePaletteToggle /> を追加 (ConnectedIntlProvider 内)

挙動:
- 編集中にドロワーハンドルが左端に表示される (▶ または ◀)
- ▶ をタップ: パレット表示 (ハンドルは ◀ に)
- ◀ をタップ: パレット非表示 (ハンドルは ▶ に)

upstream への影響:
- なし (palette-visibility は元々 Smalruby reducer)

未対応 (フォローアップ):
- ブロックドラッグ開始時の自動クローズ:
  Blockly の workspace.addChangeListener から drag start を検知して
  hidePalette() を呼ぶ。ScratchBlocks へのアクセスが要るので別 PR で
  実装する想定 (blocks-gesture-recovery と同じパターンで)。

検証 (Playwright, viewport 390x844):
- mobile_gui=1 で初期状態: パレット非表示、▶ ハンドルが左端に表示
- ▶ クリック → パレット表示 + ハンドルが ◀ に
- ◀ クリック → パレット非表示 + ハンドルが ▶ に
- ユニットテスト 8/8

Refs #572

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

takaokouji and others added 3 commits April 30, 2026 01:33
… rev)

issue #572 Phase 2-D のフィードバック対応:

1. 新規 MobilePaletteToggle コンポーネントを削除
   - 既存の Smalruby PaletteToggle (PC でも使われている) を流用
   - ボタン 2 つで混乱するという指摘 → 既存のものを残す方針

2. PaletteToggle を狭幅画面でタップしやすく拡大
   - palette-toggle.css に @media (max-width: 767px) ブロックを追加
   - サイズ 16x48 → 28x56、紫の背景、白文字、太字
   - PC (>= 768px) では従来サイズのまま

3. ドラッグ開始でパレット自動クローズ機能を実装
   - 新規 MobilePaletteAutoCloser コンポーネント (描画なし)
   - useEffect で document に pointerdown listener を仕掛ける
   - イベント対象が SVG class="blocklyFlyout" 配下なら、続く pointermove
     で 5px 以上動いた瞬間に hidePalette() を dispatch
   - タップだけでは閉じない (dx/dy を計算して threshold 判定)
   - 単純なタップで閉じないので誤動作を防げる
   - scratch-blocks に明確な BLOCK_DRAG_START イベントが無い (DRAG_OUTSIDE
     と END_DRAG しか expose されていない) ため DOM レベルで検知

4. mobile_gui モード突入時の自動非表示は MobilePaletteAutoCloser に集約
   - useRef で初回フラグを保持し 1 回だけ hidePalette()

検証 (Playwright, viewport 390x844):
- ?mobile_gui=1 で初期表示: パレット非表示、既存 ◀/▶ ハンドル拡大版
- ◀ クリック → パレット表示、▶ クリック → 非表示
- ユニットテスト 2/2 (mobile-palette-auto-closer)

Refs #572

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e (Phase 2-D rev)

issue #572 Phase 2-D のフィードバック対応:

1. 起動時のパレット自動非表示を撤回
   - 要望: mobile_gui モード突入時もパレットは表示しておきたい
   - MobilePaletteAutoCloser から useEffect の auto-hide ロジックを削除

2. ドラッグ開始でパレットを閉じる仕組みを scratch-blocks の
   `Blockly.Events.DRAG_OUTSIDE` 購読に変更
   - 旧: DOM の pointerdown / pointermove で 5px 以上の移動を検出
   - 旧の問題:
     a) 単純なフライアウト内スクロールも誤って発火させる
     b) hidePalette() を gesture 進行中に dispatch すると Blockly の
        WorkspaceDragger の `metrics.contentLeft` が null になり
        `Cannot read properties of null (reading 'contentLeft')` でクラッシュ
   - 新: DRAG_OUTSIDE は「block が flyout から出て workspace に入った」時点
     で発火するため、drag が確実に成立してからの dispatch で安全
     かつ flyout 内スクロールでは発火しない

検証 (Playwright, viewport 390x844):
- 初期状態: パレット表示 ✓
- workspace.fireChangeListener({type: 'dragOutside'}) を手動発火
  → flyout / toolbox の display が none に切り替わる ✓
- 実機 (iPhone Safari / Chrome 実機) での block drag は OS の touch ↔
  pointer event 経由で Blockly が DRAG_OUTSIDE を発火 (Playwright の
  dragTo は HTML5 drag を使うため synthetic test では発火しない)

Refs #572

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2-D rev2: 検証ログから DRAG_OUTSIDE は workspace 内 drag では発火しないことが
判明したため、フライアウトからのブロック drag → workspace 投下のシグナルとして
Events.CREATE を購読し、`workspace.currentGesture_` が立っている (= ユーザーの手の
動きで drag 中) ときだけ hidePalette を dispatch する。

プロジェクト読み込み / undo 時の CREATE は currentGesture_ が無いため誤発火しない。
@takaokouji takaokouji merged commit f728ea4 into develop Apr 29, 2026
9 checks passed
@takaokouji takaokouji deleted the fix/issue-572-phase-2d-palette-drawer branch April 29, 2026 17:27
github-actions Bot pushed a commit that referenced this pull request Apr 29, 2026
…-phase-2d-palette-drawer

feat(gui): add mobile palette drawer toggle (Phase 2-D of #572, drag-close TODO)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant